package com.maxmind.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.time.Duration;


import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;

import com.maxmind.common.BusinessException;
import com.maxmind.common.validate.ResCode;
import com.maxmind.db.CHMCache;
import com.maxmind.db.Reader;
import com.maxmind.domain.LookUpResult;
import com.maxmind.domain.LookupBaseResult;
import com.maxmind.service.LookUpService;

import lombok.extern.slf4j.Slf4j;

/**
 * 类LookUpServiceImpl的实现描述：ip查找实现类
 *
 * @author sunyj 2025/3/21 13:56
 */
@Service
@Slf4j
public class LookUpServiceImpl implements LookUpService {

    @javax.annotation.Resource
    private ResourceLoader resourceLoader;

    private static final String LANGUAGE_STR = "en";

    private static Reader reader; // 静态共享实例

    private static final Duration CACHE_TTL = Duration.ofHours(1);
    private static final int MAX_CACHE_SIZE = 50_000;

    private final Cache<String, LookUpResult> ipCache = Caffeine.newBuilder()
            .maximumSize(MAX_CACHE_SIZE)
            .expireAfterWrite(CACHE_TTL)
            .recordStats()
            .build();


    @PostConstruct
    public void init() throws IOException {
        Resource resource = resourceLoader.getResource("classpath:data/GeoLite2-City.mmdb");
        if (!resource.exists()) {
            throw new BusinessException(ResCode.ORDER_ERROR_1003_DESC, "资源文件不存在");
        }
        InputStream inputStream = resource.getInputStream();
        reader = new Reader(inputStream, new CHMCache()); // 初始化单例
    }

    @PreDestroy
    public void destroy() {
        if (reader != null) {
            try {
                reader.close(); // 确保关闭资源
            } catch (IOException e) {
                log.error("关闭Reader失败", e);
            }
        }
    }


    @Override
    public LookUpResult getResultByIpStr(String ip) {
        //增加缓存
        try {
            LookUpResult result = ipCache.getIfPresent(ip);
            if (result == null) {
                result = resolveIpWithCache(ip);
            }
            return result;
        } catch (IOException e) {
            log.error("反向解析定位失败", e);
            throw new BusinessException(ResCode.ORDER_ERROR_1003_DESC, "反向解析定位失败");
        } catch (Exception e) {
            log.error("系统异常", e);
            throw new BusinessException(ResCode.ORDER_ERROR_1003_DESC, "系统异常");
        }
    }

    private LookUpResult resolveIpWithCache(String ip) throws IOException {
        InetAddress address = InetAddress.getByName(ip);
        LookupBaseResult baseResult = reader.get(address, LookupBaseResult.class);
        return convertToLookUpResult(baseResult);
    }


    /**
     * 将LookupBaseResult转换为LookUpResult
     */
    private LookUpResult convertToLookUpResult(LookupBaseResult baseResult) {
        if (baseResult == null) {
            return null;
        }
        LookUpResult result = new LookUpResult();
        String languageStr = LANGUAGE_STR;
        //封装城市
        if (baseResult.getCountry() != null) {
            result.setIsoCode(baseResult.getCountry().getIsoCode());
            if ("CN".equals(baseResult.getCountry().getIsoCode())) {
                languageStr = "zh-CN";
            }
            if (baseResult.getCountry().getNames() != null) {
                result.setCountryName(baseResult.getCountry().getNames().get(languageStr));
                if (result.getCountryName() == null) {
                    result.setCountryName(baseResult.getCountry().getNames().get(LANGUAGE_STR));
                }
            }
        } else {
            result.setIsoCode(null);
            result.setCountryName(null);
        }

        // 封装洲
        if (baseResult.getContinent() != null) {
            result.setContinentCode(baseResult.getContinent().getCode());
            if (baseResult.getContinent().getNames() != null) {
                result.setContinentName(baseResult.getContinent().getNames().get(languageStr));
                if (result.getContinentName() == null) {
                    result.setContinentName(baseResult.getContinent().getNames().get(LANGUAGE_STR));
                }
            }
        } else {
            result.setContinentCode(null);
            result.setContinentName(null);
        }

        // 封装地理位置
        if (baseResult.getLocation() != null) {
            result.setTimeZone(baseResult.getLocation().getTimeZone());
            result.setLatitude(baseResult.getLocation().getLatitude());
            result.setLongitude(baseResult.getLocation().getLongitude());
        } else {
            result.setTimeZone(null);
            result.setLatitude(null);
            result.setLongitude(null);
        }

        return result;
    }
}
